#include "logMessage.hpp"

#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;

#include "Protocal.hpp"

enum
{
    SOCKET_ERR = 1,
    USAGE_ERR,
    CONNECT_ERR,
};

class CalClient
{
public:
    CalClient(const string &serverip, const uint16_t &serverport)
        : _sock(-1), _serverIP(serverip), _serverPort(serverport)
    {
    }
    ~CalClient()
    {
        close(_sock);
    }

    void InitClient()
    {
        // 1.创建套接字
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            logMessage(FATAL, "Create Socket FAIL!");
            exit(SOCKET_ERR);
        }
        logMessage(NORMAL, "Create Socket Success!");

        // 2. 不需要显示的bind，OS会自动bind，在发起链接的时候
        // 3. No need listen    4. No need accept
    }

    void Start()
    {
        // 5. 要发起链接 connect
        struct sockaddr_in server;
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverPort);
        server.sin_addr.s_addr = inet_addr(_serverIP.c_str());

        if (connect(_sock, (struct sockaddr *)&server, sizeof(server)) != 0)
        {
            // 发起连接fail
            logMessage(FATAL, "Connect Socket Fail!");
            exit(CONNECT_ERR);
        }

        string line;
        string inbuffer;
        for (;;)
        {
            // 网络计算器 # 1+1  234*678 格式
            cout << "Please Enter# ";
            getline(cin, line);            // 1+1
            Request req = ParseLine(line); // 解析成 "1 + 1" 将这个结构化对象send
            string content;
            // 序列化
            req.Serialize(&content);
            // 添加报头
            string send_string = enLength(content);
            //客户端这里的添加报头
            //cout << "客户端这里的添加协议报头的报文为: " << send_string << endl;

            // 将报文发送出去
            send(_sock, send_string.c_str(), send_string.size(), 0); // 阻塞发送
            //cout << "客户端发送报文成功!" << endl;

            // success 上面 --------------------------------------------
            // TODO ...
            //  收报文
            string package, text;
            if (!recvPackage(_sock, inbuffer, &package))
            {
                continue;
            }
            // 到这里 就是一个有效报文  "content_len"\r\n"x op y"\r\n
            if (!deLength(package, &text))
            {
                continue;
            }

            // 到这里 "x op y" 需要进行反序列化
            Response res;
            res.deSerialize(text);
            cout << "[exitCode]#-> " << res._exitCode << endl;
            cout << "[result]#-> " << res._result << endl;
        }
    }

    Request ParseLine(const string &line)
    {
        int status = 0; // 0为碰到操作符之前，1为碰到操作符，2为碰到操作符之后
        string left, right;
        int i = 0;
        char op;
        int length = line.size();
        while (i < length)
        {
            switch (status)
            {
            case 0:
                // 碰到操作符的时候
                if (!isdigit(line[i]))
                {
                    op = line[i]; // 此时无++
                    status = 1;
                }
                else
                {
                    left.push_back(line[i++]);
                }
                break;
            case 1:
                i++;
                status = 2;
                break;
            case 2:
                right.push_back(line[i++]);
                break;
            default:
                break;
            }
        }

        // 开始构建结构化对象
        cout << stoi(left) << " " << stoi(right) << " " << op << endl;
        return Request(stoi(left), stoi(right), op);
    }

private:
    int _sock;
    string _serverIP;
    uint16_t _serverPort;
};